/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "PointBuffer.h"
#include "Hardware.h"
#include <Gluck.h>

namespace liba
{
namespace lib3d
{
namespace hard
{
namespace directx8
{

PointBuffer::PointBuffer(Hardware * hardware)
:	Dependent( hardware ),
	valid_flag( false ),
	vertex_buffer( 0 ),
	vertices_count( 0 ),
	allocated_count( 0 ),
	stride( 0 )
{}

PointBuffer::~PointBuffer()
{
	release();
}

bool PointBuffer::is_valid()const
{
	return valid_flag;
}

bool PointBuffer::update(
		const float * positions, int positions_count,
		const float * diffuse_colors, int diffuse_colors_count,
		const float * sizes, int sizes_count )
{
	if( !hardware->is_operational() )
		return true;
/*	{
		allocated_count = 0;
		if ( vertex_buffer )
			vertex_buffer->Release(); vertex_buffer = 0;
		valid_flag = true;
	}*/

	int count = positions_count/3;
	this->world_size = world_size;
	stride = 7 * sizeof(float) + sizeof(DWORD);

	if( !valid_flag || count > allocated_count )
	{
		if ( vertex_buffer )
			vertex_buffer->Release(); vertex_buffer = 0;

		vertices_count = count;
		if( vertices_count == 0 )
		{
			valid_flag = true;
			return true;
		}

		allocated_count = count + 100;
		DWORD flags = 0;
		if( !hardware->can_hw_vshaders() )
			flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
		hardware->get_device()->CreateVertexBuffer( stride*allocated_count, flags | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS /*| D3DUSAGE_DYNAMIC*/, 0, D3DPOOL_DEFAULT, &vertex_buffer, 0 );

		if ( !vertex_buffer )
			 throw Gluck(__FUNCTION__, "create_internal_vertex_buffer() failed");
	}
	vertices_count = count;
	if( vertices_count == 0 )
	{
		valid_flag = true;
		return true;
	}

	DWORD size = 0;
	float * data = 0;
	HRESULT hr = vertex_buffer->Lock( 0, 0, (void**)&data, 0/*D3DLOCK_DISCARD*/ );
	if ( FAILED(hr) )
		throw Gluck(__FUNCTION__, "vertex_buffer->Lock() failed");

	for( int i = 0; i < count; ++i )
	{
		*data++ = *positions++;
		*data++ = *positions++;
		*data++ = *positions++;
		*data++ = *sizes++;
		float r = *diffuse_colors++;
		float g = *diffuse_colors++;
		float b = *diffuse_colors++;
		float a = *diffuse_colors++;
		*reinterpret_cast<DWORD*>(data++) = hardware->get_dword_color( r, g, b, a );
	}
	vertex_buffer->Unlock();

	valid_flag = true;
	return true;
}

void PointBuffer::render( int vertex_pos, int primitive_count )
{
	if( vertices_count == 0 || !hardware->is_operational() )
		return;
	HRESULT hr = 0;

	hr = hardware->get_device()->SetStreamSource( 0, vertex_buffer, 0, stride );
	hr = hardware->get_device()->DrawPrimitive( D3DPT_POINTLIST, vertex_pos, primitive_count );
}

void PointBuffer::invalidate()
{
	valid_flag = false;
	if( vertex_buffer )
		int ref_count = vertex_buffer->Release();
	vertex_buffer = 0;
	allocated_count = 0;
}

void PointBuffer::release()
{
	valid_flag = false;

	if( vertex_buffer )
		int ref_count = vertex_buffer->Release();
	vertex_buffer = 0;
}

} // namespace directx8
} // namespace hard
} // namespace lib3d
} // namespace liba

